package com.eyas.im.client;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;

public final class TaskCompleteFuture implements Comparable<TaskCompleteFuture> {
    private long generateTime = System.nanoTime();
    private WriteCallbackFunction writeCallbackFunction;
    private AtomicBoolean doneFlag = new AtomicBoolean(false);
    private LinkedList<Thread> waitNodes = new LinkedList<>();
    private Lock lock = new ReentrantLock();

    public TaskCompleteFuture(WriteCallbackFunction writeCallbackFunction) {
        this.writeCallbackFunction = writeCallbackFunction;
    }

    /**
     * 判断write任务是否完成
     *
     * @return
     */
    public boolean isDone() {
        return doneFlag.get();
    }

    public void sync() {
        this.sync(0,null);
    }

    public void sync(long timeout, TimeUnit unit) {
        boolean needPark = false;
        if(!doneFlag.get()) {
            try {
                lock.lock();
                if(!doneFlag.get()) {
                    needPark = true;
                    waitNodes.add(Thread.currentThread());
                }
            }finally {
                lock.unlock();
            }
        }
        if(needPark) {
            if(unit!=null&&timeout>0)
                LockSupport.parkNanos(TimeUnit.NANOSECONDS.convert(timeout,unit));
            else
                LockSupport.park();
        }

    }

    /**
     * 任务执行结束
     */
    public void complete(Throwable throwable) {
        doneFlag.compareAndSet(false, true);
        try {
            lock.lock();
            for(Thread thread:this.waitNodes) {
                LockSupport.unpark(thread);
            }
        }finally {
            lock.unlock();
        }
        if(this.writeCallbackFunction!=null)
            writeCallbackFunction.callback(throwable);
    }

    @Override
    public int compareTo(TaskCompleteFuture o) {
        return Long.compare(this.generateTime, o.generateTime);
    }
}
